/**
 * *****************************************************************
 * @file    adt3102_tinyframe.h
 * @author  Jack(jackg@andartechs.com.cn)
 * @version 1.0.0
 * @date    2022-02-10
 * @brief   
 *                 Copyright (c) 2022, Andar Technologies Inc.
 *                           www.andartechs.com 
 *
 * *****************************************************************
 */
#ifndef __TINY_FRAME_H
#define __TINY_FRAME_H


/*------------------------------- include ------------------------------------*/
#include "adt3102_type_define.h"
#include "adt3102_tf_config.h"
#include <stdint.h>  // for uint8_t etc
#include <stdbool.h> // for bool
#include <stddef.h>  // for NULL
#include <string.h>  // for memset()
#include "adt3102_type_define.h"
#include "uart_ctype_map.h"
//---------------------------------------------------------------------------



/*------------------------------- define -------------------------------------*/
// Checksum type (0 = none, 8 = ~XOR, 16 = CRC16 0x8005, 32 = CRC32)
#define TF_CKSUM_NONE   0   // no checksums
#define TF_CKSUM_XOR    8   // inverted xor of all payload bytes
#define TF_CKSUM_CRC8   9   // Dallas/Maxim CRC8 (1-wire)
#define TF_CKSUM_CRC16  16  // CRC16 with the polynomial 0x8005 (x^16 + x^15 + x^2 + 1)
#define TF_CKSUM_CRC32  32  // CRC32 with the polynomial 0xedb88320
#define TF_CKSUM_CUSTOM8  1 // Custom 8-bit checksum
#define TF_CKSUM_CUSTOM16 2 // Custom 16-bit checksum
#define TF_CKSUM_CUSTOM32 3 // Custom 32-bit checksum

#define TF_RX_BUF_SIZE      128
#define TARGET_NUM          256
#define ADC_NUM             SAMPLE_POINT*2


#if TF_LEN_BYTES == 1
    typedef uint8_t TF_LEN;
#elif TF_LEN_BYTES == 2
    typedef uint16_t TF_LEN;
#elif TF_LEN_BYTES == 4
    typedef uint32_t TF_LEN;
#else
    #error Bad value of TF_LEN_BYTES, must be 1, 2 or 4
#endif

#if TF_TYPE_BYTES == 1
    typedef uint8_t TF_TYPE;
#elif TF_TYPE_BYTES == 2
    typedef uint16_t TF_TYPE;
#elif TF_TYPE_BYTES == 4
    typedef uint32_t TF_TYPE;
#else
    #error Bad value of TF_TYPE_BYTES, must be 1, 2 or 4
#endif

#if TF_ID_BYTES == 1
    typedef uint8_t TF_ID;
#elif TF_ID_BYTES == 2
    typedef uint16_t TF_ID;
#elif TF_ID_BYTES == 4
    typedef uint32_t TF_ID;
#else
    #error Bad value of TF_ID_BYTES, must be 1, 2 or 4
#endif

#if (TF_CKSUM_TYPE == TF_CKSUM_XOR) || (TF_CKSUM_TYPE == TF_CKSUM_NONE) || (TF_CKSUM_TYPE == TF_CKSUM_CUSTOM8) || (TF_CKSUM_TYPE == TF_CKSUM_CRC8)
    // ~XOR (if 0, still use 1 byte - it won't be used)
    typedef uint8_t TF_CKSUM;
#elif (TF_CKSUM_TYPE == TF_CKSUM_CRC16) || (TF_CKSUM_TYPE == TF_CKSUM_CUSTOM16)
    // CRC16
    typedef uint16_t TF_CKSUM;
#elif (TF_CKSUM_TYPE == TF_CKSUM_CRC32) || (TF_CKSUM_TYPE == TF_CKSUM_CUSTOM32)
    // CRC32
    typedef uint32_t TF_CKSUM;
#else
    #error Bad value for TF_CKSUM_TYPE
#endif


/*------------------------------- Typedef ------------------------------------*/
/** Peer bit enum (used for init) */
typedef enum
{
    TF_SLAVE    = 0,
    TF_MASTER   = 1,
} TF_Peer;

/** Response from listeners */
typedef enum
{
    TF_NEXT     = 0,    // Not handled, let other listeners handle it
    TF_STAY     = 1,    // Handled, stay
    TF_RENEW    = 2,    // Handled, stay, renew - useful only with listener timeout
    TF_CLOSE    = 3,    // Handled, remove self
} TF_Result;

enum TF_State_ {
    TFState_SOF = 0,      //!< Wait for SOF
    TFState_LEN,          //!< Wait for Number Of Bytes
    TFState_HEAD_CKSUM,   //!< Wait for header Checksum
    TFState_ID,           //!< Wait for ID
    TFState_TYPE,         //!< Wait for message type
    TFState_DATA,         //!< Receive payload
    TFState_DATA_CKSUM    //!< Wait for Checksum
};

#if ADT_TF_TYPE==0x0A00
typedef struct targetInfo
{
    float range;
    float velocity;
    float power;
    float phase0;
    float phase1;
    float angleH;
    float angleV;
} OneTargetInfoStrTypedef;
#elif ADT_TF_TYPE==0x0A01
typedef struct targetInfo
{
    float range;
    float power;
    float phase1;
    float angleH;
} OneTargetInfoStrTypedef;
#elif ADT_TF_TYPE==0x0A02
typedef struct targetInfo
{
    float range;
    float phase1;
} OneTargetInfoStrTypedef;
#elif ADT_TF_TYPE==0x0A03
typedef struct targetInfo
{
    float rate;

} OneTargetInfoStrTypedef;
#elif ADT_TF_TYPE==0x0A04
typedef struct targetInfo
{
    float x;
    float y;
    int32  dop_idx;
    int32 cluster_id;

} OneTargetInfoStrTypedef;
#elif ADT_TF_TYPE==0x0A05
typedef struct targetInfo
{
    float x;
    float y;
    int32  dop_idx;
    int32 cluster_id;

} OneTargetInfoStrTypedef;
#elif ADT_TF_TYPE==0x0A08
typedef struct targetInfo
{
    float x;
    float y;
    int32  dop_idx;
    int32 cluster_id;

} OneTargetInfoStrTypedef;
#elif ADT_TF_TYPE==0x0A10
typedef struct targetInfo
{
    float range;
    float velocity;
    float power;
    uint32 detected;

} OneTargetInfoStrTypedef;
#elif ADT_TF_TYPE==0x0A11
typedef struct targetInfo
{
    int32 cluster_id;
    float x;
    float y;
    float z; 
    uint32 power;
    float dopIdx;
} OneTargetInfoStrTypedef;
#else
typedef struct targetInfo
{
    float range;
    //float velocity;
    //float power;
    //uint32 detected;
} OneTargetInfoStrTypedef;
#endif

typedef struct
{
    uint32 targetNum;
    OneTargetInfoStrTypedef multTargetStr[TARGET_NUM];
} multTargetInfoStrTypedef;

typedef struct
{
    uint16 targetFound;
    uint16 targetLose;
} targetStateStrTypedef;

typedef struct 
{
    uint32 measureCommand;
    uint32 measureType;

} HumanMeausureReqStrTypedef;

typedef struct 
{
    uint32 measureType;
    float  power;

} HumanMeausureRspStrTypedef;

//adt3012 Rx frame design
/**
  TYPE  | data type | 
 0x0100 |   float   | powerThresold
 0x0101 |   uint32  | rmStaticTarget
 0x0102 |   uint32  | getStaticTarget
 0x0103 |   float   | velocityThresold
*/
typedef struct 
{
    uint16 receiveType;
    uint16 recvLen;

    union {
        int32 revuint32Data;
        float revfloatData;
        HumanMeausureReqStrTypedef measureReqStr;
    }u;

} TinyFrameRxStrTypedef;

typedef struct
{
    uint8 project;
    uint8 versionMajor;
    uint8 versionMinor;
    uint8 versionPatch;
} verStatusStrTypedef;

typedef struct
{
    int32 status;
    float noisefloor;
} noiseFloorStatusStrTypedef;

typedef struct 
{
    float powerThreshold;
    int32 rangeMax;
    int32 pwmHoldTime;
    int32 luxControl;
} HumanConfigStatusStrTypedef;

typedef struct 
{
    float powerThreshold;
    float noiseFloorAverage;
    float noiseFloorMax;
} HumanNoiseStatusStrTypedef;


#define MSG_CFG_MIN_DETECT_POWER        (0x0100)
#define MSG_CFG_MIN_DETECT_VELOCITY     (0x0103)
#define MSG_CFG_MAX_DETECT_RANGE        (0x0104)
#define MSG_CFG_PWM_HOLD_TIME           (0x0107)
#define MSG_CFG_LUX_THRESHOLD           (0x0108)
#define MSG_CFG_OPTION_REMOVE_STATIC    (0x0109)
#define MSG_MEASUREMENT_REQUEST         (0x010A)
#define MSG_HUMAN_REPORT_FILTER_REQUEST (0x010B)
#define MSG_HUMAN_CONFIG_SRC_REQUEST    (0x010C)
#define MSG_EXPERIMENTALL_MODEL         (0x010D)
#define MSG_PRINTF_TF_ENABLE            (0x010E)
#define MSG_DETECTE_DUSOISE             (0x010F)
#define MSG_FIRMWARE_STATUS_REQUEST     (0xFFFF)
#define MSG_HUMAN_CONFIG_STATUS_REQUEST (0x2110)
#define MSG_OTA_REQUEST                 (0x3000)



#define MSG_NOISE_FLOOR_REQUEST         (0x0110)
#define MSG_VERSION_REQUEST             (0x0111)
#define MSG_UPDATE_CONFIG_REQUEST       (0x0112)

#define COMMAND_ENTER_MEASURE            (1)
#define COMMAND_QUIT_MEASURE             (0)
#define MEASURE_TYPE_NOISE               (1)
#define MEASURE_TYPE_SIGNAL              (2)

#define PWM_DELAY_30S_ID  (0)
#define PWM_DELAY_1M_ID   (1)
#define PWM_DELAY_2M_ID   (2)
#define PWM_DELAY_5M_ID   (3)
#define PWM_DELAY_10M_ID  (4)
#define PWM_DELAY_15M_ID  (5)
#define PWM_DELAY_30M_ID  (6)
#define PWM_DELAY_5S_ID   (7)
#define PWM_DELAY_0S_ID   (8)

#define MIN_VELOCITY_00_ID  (0)
#define MIN_VELOCITY_02_ID  (1)
#define MIN_VELOCITY_04_ID  (2)
#define MIN_VELOCITY_06_ID  (3)
#define MIN_VELOCITY_08_ID  (4)
#define MIN_VELOCITY_10_ID  (5)
#define MIN_VELOCITY_12_ID  (6)
#define MIN_VELOCITY_14_ID  (7)
#define MIN_VELOCITY_16_ID  (8)
#define MIN_VELOCITY_18_ID  (9)
#define MIN_VELOCITY_20_ID  (10)

#define MAX_RANGE_1ST_ID    (0)
#define MAX_RANGE_2ND_ID    (1)
#define MAX_RANGE_3RD_ID    (2)
#define MAX_RANGE_4TH_ID    (3)

#define CONTINUE_ENVIRONMENT_LEARN   (0)
#define START_AUTO_ENVIRONMENT_LEARN (1)
#define ENVIRONMENT_LEARN            (2)
#define READ_POWER_NOISE_ENV         (3)
#define RESET_EXP_INIT               (4)
#define RADAR_PWM_ON                 (5)
#define RADAR_PWM_OFF                (6)
#define RADAR_SCAN_ON                (7)
#define PWM_ON_TOOGLE                (8)
#define PWM_TOOGLE                   (9)
#define PWM_10_DUTY_CYCLE            (10)
#define PWM_30_DUTY_CYCLE            (11)


#define DETECTED_PROCESS         (0)
#define DETECTED_NOT_PROCESS     (1)


#define FILTER_OPTION_RAW_DATA_ID   (0)
#define FILTER_OPTION_PWM_DELAY_ID  (1)

#define LUX_CONTROL_OFF_ID    (0)
#define LUX_CONTROL_10_ID     (1)
#define LUX_CONTROL_30_ID     (2)
#define LUX_CONTROL_100_ID    (3)
#define LUX_CONTROL_STUDY_ID  (4)

#define CONFIG_SOURCE_COMMAND_ID    (0)
#define CONFIG_SOURCE_HARDWARE_ID   (1)


/** Data structure for sending / receiving messages */
typedef struct TF_Msg_ {
    TF_ID frame_id;       //!< message ID
    bool is_response;     //!< internal flag, set when using the Respond function. frame_id is then kept unchanged.
    TF_TYPE type;         //!< received or sent message type

    /**MAX_RANGE_4TH_ID
     * Buffer of received data, or data to send.
     *
     * - If (data == NULL) in an ID listener, that means the listener timed out and
     *   the user should free any userdata and take other appropriate actions.
     *
     * - If (data == NULL) and length is not zero when sending a frame, that starts a multi-part frame.
     *   This call then must be followed by sending the payload and closing the frame.
     */
    const uint8_t *data;
    TF_LEN len; //!< length of the payload

    /**
     * Custom user data for the ID listener.
     *
     * This data will be stored in the listener slot and passed to the ID callback
     * via those same fields on the received message.
     */
    void *userdata;
    void *userdata2;
} TF_Msg;


typedef void (*TF_Sender_Cb)(UartTypeDef *UartX, const uint8* buf, uint32 len);


/**

 * Frame parser internal state.
 */
struct TinyFrame_ {
    /* Public user data */
    void *userdata;
    uint32_t usertag;

    // --- the rest of the struct is internal, do not access directly ---

    /* Own state */
    TF_Peer peer_bit;       //!< Own peer bit (unqiue to avoid msg ID clash)
    TF_ID next_id;          //!< Next frame / frame chain ID

    /* Parser state */
    enum TF_State_ state;
    TF_TICKS parser_timeout_ticks;
    TF_ID id;               //!< Incoming packet ID
    TF_LEN len;             //!< Payload length
    uint8_t data[TF_MAX_PAYLOAD_RX]; //!< Data byte buffer
    TF_LEN rxi;             //!< Field size byte counter
    TF_CKSUM cksum;         //!< Checksum calculated of the data stream
    TF_CKSUM ref_cksum;     //!< Reference checksum read from the message
    TF_TYPE type;           //!< Collected message type number
    bool discard_data;      //!< Set if (len > TF_MAX_PAYLOAD) to read the frame, but ignore the data.

    /* Tx state */
    // Buffer for building frames
    uint8_t sendbuf[TF_SENDBUF_LEN]; //!< Transmit temporary buffer

    uint32_t tx_pos;        //!< Next write position in the Tx buffer (used for multipart)
    uint32_t tx_len;        //!< Total expected Tx length
    TF_CKSUM tx_cksum;      //!< Transmit checksum accumulator

#if !TF_USE_MUTEX
    bool soft_lock;         //!< Tx lock flag used if the mutex feature is not enabled.
#endif

    TF_Sender_Cb   sender_cb;
    UartTypeDef    *uart_port;

    // Those counters are used to optimize look-up times.
    // They point to the highest used slot number,
    // or close to it, depending on the removal order.
    TF_COUNT count_id_lst;
    TF_COUNT count_type_lst;
    TF_COUNT count_generic_lst;
};


/*------------------------------ variable ------------------------------------*/

/** TinyFrame struct typedef */
typedef struct TinyFrame_ TinyFrame;

extern volatile uint8 g_TfRxBuff[TF_RX_BUF_SIZE];
extern volatile uint32 g_TfWriteCount;


/*------------------------------ function ------------------------------------*/
/**
 * @brief   tiny frame initialization.
 * @param   None.
 * @return  None.
 * @note
 */
void tinyFrameInit(void);

/**
 * @brief   enable printfTf.
 * @param   Enable:
 * @return  None.
 * @note
 */
void setPrintfTfEnable(uint8 enable);

/**
 * @brief   uart receive data through tinyframe protocol.
 * @param   None.
 * @return  TinyFrameRxStrTypedef: return data type val.
 * @note
 */
TinyFrameRxStrTypedef tinyFramefRx(void);

/**
 * @brief   Accept a single incoming byte.
 * @param   tf: instance.
 * @param   c: a received char.
 * @return  accept state {fail =0;sucesse =0xff}.
 * @note
 */
int8 TF_AcceptChar(TinyFrame *tf, unsigned char c);

/**
 * @brief   uart send data through tinyframe protocol
 * @param   type:   send data type.
 * @param   data:   send data address.
 * @param   len:    send data len.
 * @return  None.
 * @note
 */
void tinyFramefTx(TF_TYPE type, uint8 *data, TF_LEN len);

/**
 * @brief   send without listener and struct
 * @param   tf: instance.
 * @param   type:   send data type.
 * @param   data:   send data address.
 * @param   len:    send data len.
 * @return  None.
 * @note
 */
bool TF_SendSimple(TinyFrame *tf, TF_TYPE type, const uint8_t *data, TF_LEN len);

/**
 * @brief   send without listener.
 * @param   tf: instance.
 * @param   msg: message written to the buffer
 * @return  True/False.
 * @note
 */
bool TF_Send(TinyFrame *tf, TF_Msg *msg);


void TF_UartSend(UartTypeDef *UartX, const uint8* buf, uint32 len);


void TF_send_packet(TF_TYPE type, uint8 *data, TF_LEN len);

/**
 * @brief   send with a listener waiting for a reply, without the struct.
 * @param   tf: instance.
 * @param   type:   send data type.
 * @param   data:   send data address.
 * @param   len:    send data len.
 * @param   timeout:.
 * @return  nr of bytes in outbuff used
 * @note
 */
bool TF_QuerySimple(TinyFrame *tf, TF_TYPE type, \
        const uint8_t *data, TF_LEN len, TF_TICKS timeout);


/**
 * @brief   send with a listener waiting for a reply.
 * @param   tf: instance.
 * @param   msg: message written to the buffer.
 * @param   timeout:.
 * @return  True/False.
 * @note
 */
bool TF_Query(TinyFrame *tf, TF_Msg *msg, TF_TICKS timeout);

/**
 * @brief   uart sends printing information to GUI through tinyframe protocol.
 * @param   format:
 * @return  True/False.
 * @note
 */
int16 printfTf(const char *format, ...);

/**
 * @brief   Like TF_Send, but with explicit frame ID (set inside the msg object), 
 *          use for responses.
 * @param   tf: instance.
 * @param   msg: message written to the buffer.
 * @return  True/False.
 * @note
 */
bool TF_Respond(TinyFrame *tf, TF_Msg *msg);


// Mutex functions
#if TF_USE_MUTEX

    /** Claim the TX interface before composing and sending a frame */
    extern bool TF_ClaimTx(TinyFrame *tf);

    /** Free the TX interface after composing and sending a frame */
    extern void TF_ReleaseTx(TinyFrame *tf);

#endif

// Custom checksum functions
#if (TF_CKSUM_TYPE == TF_CKSUM_CUSTOM8) || (TF_CKSUM_TYPE == TF_CKSUM_CUSTOM16) || (TF_CKSUM_TYPE == TF_CKSUM_CUSTOM32)

    /**
     * Initialize a checksum
     *
     * @return initial checksum value
     */
    extern TF_CKSUM TF_CksumStart(void);

    /**
     * Update a checksum with a byte
     *
     * @param cksum - previous checksum value
     * @param byte - byte to add
     * @return updated checksum value
     */
    extern TF_CKSUM TF_CksumAdd(TF_CKSUM cksum, uint8_t byte);

    /**
     * Finalize the checksum calculation
     *
     * @param cksum - previous checksum value
     * @return final checksum value
     */
    extern TF_CKSUM TF_CksumEnd(TF_CKSUM cksum);

#endif

#endif
